package club.kingyin.kyblogprogateway.filter;

import club.kingyin.commons.clients.UserClient;
import club.kingyin.commons.constant.LogConstant;
import club.kingyin.commons.entity.user.Log;
import club.kingyin.commons.entity.user.User;
import club.kingyin.commons.enums.BlogEnum;
import club.kingyin.commons.response.Result;
import club.kingyin.commons.response.ResultCode;
import club.kingyin.commons.utils.RequestUtils;
import club.kingyin.easytoken.core.EasyToken;
import club.kingyin.easytoken.core.TokenPramAdapter;
import club.kingyin.kyblogprogateway.core.PathFilters;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.reactivestreams.Publisher;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.NettyWriteResponseFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

// 登录成功的结果处理成token返回，更新登录日志原始信息
@Slf4j
@Component
public class ResponseTokenFilter implements GlobalFilter, Ordered {

    @Autowired
    private EasyToken easyToken;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String value = request.getPath().value();

        ServerHttpResponse originalResponse = exchange.getResponse();
        DataBufferFactory bufferFactory = originalResponse.bufferFactory();
        ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
            @Override
            public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                if (body instanceof Flux) {
                    Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body;
                    return super.writeWith(fluxBody.buffer().map(dataBuffer -> {
                        //dataBuffer合并成一个，解决获取结果不全问题
                        DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
                        DataBuffer join = dataBufferFactory.join(dataBuffer);
                        byte[] content = new byte[join.readableByteCount()];
                        join.read(content);
                        DataBufferUtils.release(join);
                        String responseData = new String(content, StandardCharsets.UTF_8);
                        Result result = RequestUtils.getResult(responseData);

                        //修改response之后的字符串为token
                        Log log = new Log();
                        byte[] uppedContent = responseData.getBytes(StandardCharsets.UTF_8);

                        if ("/user/login".equals(value)) {
                            String username;
                            Integer id;
                            username = result.isSuccess()?((JSONObject) result.getData()).getString("username"):null;
                            id = result.isSuccess()?((JSONObject) result.getData()).getInteger("id"):null;
                            log.setUserid(id);
                            if (result.isSuccess()) {
                                String token;
                                HashMap<String, String> success = new HashMap<>();
                                success.put("role",((JSONObject) result.getData()).getString("role"));
                                if ((token = redisTemplate.opsForValue().get(username)) == null) {
                                    // 使用自研的easyToken生成加密TOKEN
                                    token = easyToken.getToken(result.getData(),(TokenPramAdapter<JSONObject>) object-> {
                                        HashMap<String, Object> map = new HashMap<>();
                                        for (String s : object.keySet()) {
                                            switch (s) {
                                                case "status":
                                                case "sex":
                                                case "role":
                                                case "titled":
                                                    map.put(s,BlogEnum.deBlogEnum(String.valueOf(object.get(s))));
                                                    continue;
                                            }
                                            map.put(s, object.get(s));
                                        }
                                        return map;
                                    });
                                    // 需要保存至redis... 7d
                                    String user = JSON.toJSONString(result.getData());
                                    redisTemplate.opsForValue().set(username,token,7,TimeUnit.DAYS);
                                    redisTemplate.opsForValue().set(token,user, 7, TimeUnit.DAYS);
                                }
                                success.put("token",token);
                                responseData = JSON.toJSONString(Result.success(success));
                                uppedContent = responseData.getBytes();
                            }
                        }
                        if (PathFilters.LOG_PATH.intercept(value)) {
                            // 日志id
                            Integer logId = Integer.parseInt(Objects.requireNonNull(exchange.getRequest().getHeaders().getFirst(LogConstant.LOG_ID)));
                            log.setId(logId);
                            log.setResponse(JSONObject.parseObject(responseData));
                            // 发送更新日志消息
                            rabbitTemplate.convertAndSend("log.direct","update",log);
                        }
                        // 写入
                        return bufferFactory.wrap(uppedContent);
                    }));
                }
                // if body is not a flux. never got there.
                return super.writeWith(body);
            }
        };
        // replace response with decorator
        return chain.filter(exchange.mutate().response(decoratedResponse).build());
    }
    @Override
    public int getOrder() {
        return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER - 1;
    }


}
